package com.andova.manager

import android.app.Application
import android.content.Context
import android.text.TextUtils
import com.google.gson.Gson
import com.google.gson.JsonSyntaxException

data class IntA(var value: Int, var what: Int, var arg1: Int, var arg2: Int, var obj: Any?)
data class LongA(var value: Long, var what: Int, var arg1: Int, var arg2: Int, var obj: Any?)
data class FloatA(var value: Float, var what: Int, var arg1: Int, var arg2: Int, var obj: Any?)
data class StringA(var value: String, var what: Int, var arg1: Int, var arg2: Int, var obj: Any?)
data class BooleanA(var value: Boolean, var what: Int, var arg1: Int, var arg2: Int, var obj: Any?)

class CacheManager {
    companion object {
        const val SHARED_PREFERENCE_NAME_DATA_CACHE = "shared.preference.name_DATA_CACHE"

        @Volatile
        private var manager: CacheManager? = null
        fun singleton(): CacheManager {
            if (manager == null) synchronized(CacheManager::class.java) { if (manager == null) manager = CacheManager() }
            return manager!!
        }
    }

    private var application: Application? = null
    private val gson = Gson()
    private var spName = SHARED_PREFERENCE_NAME_DATA_CACHE

    fun initialize(application: Application?, sharedPrefName: String? = null) {
        this.application = application
        if (sharedPrefName.isNullOrEmpty()) return
        this.spName = sharedPrefName
    }

    fun edit(key: String, value: String?) = application?.getSharedPreferences(spName, Context.MODE_PRIVATE)?.edit()?.putString(key, value)?.apply()
    fun edit(key: String, value: Int) = application?.getSharedPreferences(spName, Context.MODE_PRIVATE)?.edit()?.putInt(key, value)?.apply()
    fun edit(key: String, value: Long) = application?.getSharedPreferences(spName, Context.MODE_PRIVATE)?.edit()?.putLong(key, value)?.apply()
    fun edit(key: String, value: Float) = application?.getSharedPreferences(spName, Context.MODE_PRIVATE)?.edit()?.putFloat(key, value)?.apply()
    fun edit(key: String, value: Boolean) = application?.getSharedPreferences(spName, Context.MODE_PRIVATE)?.edit()?.putBoolean(key, value)?.apply()
    fun edit(key: String, value: Set<String?>?) = application?.getSharedPreferences(spName, Context.MODE_PRIVATE)?.edit()?.putStringSet(key, value)?.apply()
    fun clear() = application?.getSharedPreferences(spName, Context.MODE_PRIVATE)?.edit()?.clear()?.apply()
    fun editJson(key: String, value: Any?) {
        application ?: return
        val data: String = gson.toJson(value)
        if (TextUtils.isEmpty(data)) return
        application?.getSharedPreferences(spName, Context.MODE_PRIVATE)?.edit()?.putString(key, data)?.apply()
    }

    fun getString(key: String): String? = getString(key, "")
    fun getString(key: String, defValue: String?): String? = application?.getSharedPreferences(spName, Context.MODE_PRIVATE)?.getString(key, defValue) ?: defValue
    fun getStringSet(key: String): Set<String?>? = getStringSet(key, null)
    fun getStringSet(key: String, defValue: Set<String?>?): Set<String?>? = application?.getSharedPreferences(spName, Context.MODE_PRIVATE)?.getStringSet(key, defValue) ?: defValue
    fun getInt(key: String): Int = getInt(key, -1)
    fun getInt(key: String, defValue: Int): Int = application?.getSharedPreferences(spName, Context.MODE_PRIVATE)?.getInt(key, defValue) ?: defValue
    fun getLong(key: String): Long = getLong(key, -1L)
    fun getLong(key: String, defValue: Long): Long = application?.getSharedPreferences(spName, Context.MODE_PRIVATE)?.getLong(key, defValue) ?: defValue
    fun getFloat(key: String): Float = getFloat(key, -1f)
    fun getFloat(key: String, defValue: Float): Float = application?.getSharedPreferences(spName, Context.MODE_PRIVATE)?.getFloat(key, defValue) ?: defValue
    fun getBoolean(key: String): Boolean = getBoolean(key, false)
    fun getBoolean(key: String, defValue: Boolean): Boolean = application?.getSharedPreferences(spName, Context.MODE_PRIVATE)?.getBoolean(key, defValue) ?: defValue
    fun <T> getJson(key: String, model: Class<T>): T? {
        application ?: return null
        val data: String = application?.getSharedPreferences(spName, Context.MODE_PRIVATE)?.getString(key, "") ?: ""
        return try {
            gson.fromJson(data, model)
        } catch (e: JsonSyntaxException) {
            null
        } catch (e: NullPointerException) {
            null
        }
    }

    fun editWhatI(key: String, what: Int) {
        val a = getIntA(key)
        if (a == null || a.what == what) return
        a.what = what
        editIntA(key, a)
    }

    fun editWhatL(key: String, what: Int) {
        val a = getLongA(key)
        if (a == null || a.what == what) return
        a.what = what
        editLongA(key, a)
    }

    fun editWhatF(key: String, what: Int) {
        val a = getFloatA(key)
        if (a == null || a.what == what) return
        a.what = what
        editFloatA(key, a)
    }

    fun editWhatS(key: String, what: Int) {
        val a = getStringA(key)
        if (a == null || a.what == what) return
        a.what = what
        editStringA(key, a)
    }

    fun editWhatB(key: String, what: Int) {
        val a = getBooleanA(key)
        if (a == null || a.what == what) return
        a.what = what
        editBooleanA(key, a)
    }

    fun editIntA(key: String, value: Int) = editIntA(key, value, 1, 0, 0, null)
    fun editIntA(key: String, value: Int, what: Int) = editIntA(key, value, what, 0, 0, null)
    fun editIntA(key: String, value: Int, what: Int, arg1: Int, arg2: Int, obj: Any?) = editIntA(key, IntA(value, what, arg1, arg2, obj))
    fun editIntA(key: String, value: IntA) = editJson(key, value)
    fun getIntA(key: String): IntA? = getJson(key, IntA::class.java)
    fun getIntA(key: String, defValue: Int): IntA {
        val a = getIntA(key)
        return a ?: IntA(defValue, 0, 0, 0, null)
    }

    fun editLongA(key: String, value: Long) = editLongA(key, value, 1, 0, 0, null)
    fun editLongA(key: String, value: Long, what: Int) = editLongA(key, value, what, 0, 0, null)
    fun editLongA(key: String, value: Long, what: Int, arg1: Int, arg2: Int, obj: Any?) = editLongA(key, LongA(value, what, arg1, arg2, obj))
    fun editLongA(key: String, value: LongA) = editJson(key, value)
    fun getLongA(key: String): LongA? = getJson(key, LongA::class.java)
    fun getLongA(key: String, defValue: Long): LongA {
        val a = getLongA(key)
        return a ?: LongA(defValue, 0, 0, 0, null)
    }

    fun editFloatA(key: String, value: Float) = editFloatA(key, value, 1, 0, 0, null)
    fun editFloatA(key: String, value: Float, what: Int) = editFloatA(key, value, what, 0, 0, null)
    fun editFloatA(key: String, value: Float, what: Int, arg1: Int, arg2: Int, obj: Any?) = editFloatA(key, FloatA(value, what, arg1, arg2, obj))
    fun editFloatA(key: String, value: FloatA) = editJson(key, value)
    fun getFloatA(key: String): FloatA? = getJson(key, FloatA::class.java)
    fun getFloatA(key: String, defValue: Float): FloatA {
        val a = getFloatA(key)
        return a ?: FloatA(defValue, 0, 0, 0, null)
    }

    fun editStringA(key: String, value: String) = editStringA(key, value, 1, 0, 0, null)
    fun editStringA(key: String, value: String, what: Int) = editStringA(key, value, what, 0, 0, null)
    fun editStringA(key: String, value: String, what: Int, arg1: Int, arg2: Int, obj: Any?) = editStringA(key, StringA(value, what, arg1, arg2, obj))
    fun editStringA(key: String, value: StringA) = editJson(key, value)
    fun getStringA(key: String): StringA? = getJson(key, StringA::class.java)
    fun getStringA(key: String, defValue: String): StringA {
        val a = getStringA(key)
        return a ?: StringA(defValue, 0, 0, 0, null)
    }

    fun editBooleanA(key: String, value: Boolean) = editBooleanA(key, value, 1, 0, 0, null)
    fun editBooleanA(key: String, value: Boolean, what: Int) = editBooleanA(key, value, what, 0, 0, null)
    fun editBooleanA(key: String, value: Boolean, what: Int, arg1: Int, arg2: Int, obj: Any?) = editJson(key, BooleanA(value, what, arg1, arg2, obj))
    fun editBooleanA(key: String, value: BooleanA) = editJson(key, value)
    fun getBooleanA(key: String): BooleanA? = getJson(key, BooleanA::class.java)
    fun getBooleanA(key: String, defValue: Boolean): BooleanA {
        val a = getBooleanA(key)
        return a ?: BooleanA(defValue, 0, 0, 0, null)
    }
}